package players;

import model.Field;
import model.OthelloBoard;
import model.Position;


import java.util.*;


public class MinimaxPlayer implements Player 
{
	int d_searchDepth;
	Player d_evalFunc;
	
	public MinimaxPlayer(Player evalFunc, int searchDepth)
	{
		d_searchDepth = searchDepth;
		d_evalFunc = evalFunc;
	}
	
	public boolean move(OthelloBoard board, byte color) 
	{
		//System.out.println("Minimax making move...");
		ArrayList<Position> moves = board.getTransitions(color);
		
		if (moves.size() == 0) { return false; }
		
		double highestScore = 1000;
		int highestScoreIndex = 0; //if there is no difference, take the first move
		
		//start recursion
		for(int loop = 0;loop < moves.size(); ++loop ) {
			OthelloBoard tempBoard = board.getClone();
			tempBoard.makeTransition(moves.get(loop), color);
			
			double score = expandBoard(tempBoard, Field.opponent(color), d_searchDepth - 1,-1000,1000);
			
			if (score < highestScore) 
			{
				highestScore = score;
				highestScoreIndex = loop;
			}
			
		}
		
		board.makeTransition(moves.get(highestScoreIndex), color);
		
		//System.out.println("Done making move...");
		return true;
	}

	private double expandBoard(OthelloBoard bord, byte currentColor, int depth, double alpha, double beta) 
	{
		if (depth > 0) 
		{
			ArrayList<Position> moves = bord.getTransitions(currentColor);
			
			//if there are no transitions, cut off the search
			if (moves.size() == 0)
				return evaluate(bord, currentColor);
			
			//get the score for each leaf under this node and store them in boardScores
			for(int loop = 0;loop < moves.size(); ++loop ) 
			{				
				//clone the board, make a move, and expand those moves if needed
				OthelloBoard tempBoard = bord.getClone();
				tempBoard.makeTransition(moves.get(loop), currentColor);
				
				//go one level deeper, with alpha, beta and color switched:
				double new_alpha = 0 - expandBoard(tempBoard, Field.opponent(currentColor), depth - 1, 0 - beta, 0 - alpha);
				if (new_alpha > alpha)
					alpha = new_alpha;
					
				//do the pruning!
				if (alpha >= beta)
					break;
	
			}
			
			return alpha;
			
		} else 
		{
			//we have reached the lowest level, get the score
			return evaluate(bord, currentColor);
		}
		
	}
	
	public void setExploration(boolean aan) {
			
	}
	
	
	public double evaluate(OthelloBoard board, byte color)
	{
		return d_evalFunc.evaluate(board, color);
	}
	
	public String toString()
	{
		return "Minimax " + d_evalFunc.toString() + " " + d_searchDepth;
	}
}
